package com.cql.service.business.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cql.common.constant.FoodCircleConstant;
import com.cql.common.core.DO.*;
import com.cql.common.core.DTO.MomentDTO;
import com.cql.common.core.DTO.MomentInfoDTO;
import com.cql.common.core.DTO.TagDTO;
import com.cql.common.core.security.LoginUser;
import com.cql.common.exception.auth.PermissionDeniedException;
import com.cql.common.exception.moment.MomentNotExistException;
import com.cql.common.exception.moment.MomentVerifyingException;
import com.cql.common.exception.user.UserNotExistException;
import com.cql.common.utils.ServletUtils;
import com.cql.common.utils.StringUtils;
import com.cql.common.utils.ip.IpUtils;
import com.cql.mapper.MomentMapper;
import com.cql.mapper.TagMapper;
import com.cql.mapper.UserMapper;
import com.cql.service.business.AuthService;
import com.cql.service.business.MomentService;
import com.cql.service.business.RegionService;
import com.cql.service.cache.MomentCacheService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;


/**
 * @author cql
 */
@Service("momentService")
public class MomentServiceImpl extends ServiceImpl<MomentMapper, MomentDO> implements MomentService {

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private MomentMapper momentMapper;

    @Autowired
    private TagMapper tagMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private AuthService authService;

    @Autowired
    private RegionService regionService;


    @Autowired
    private MomentCacheService momentCacheService;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public MomentDTO insertOrUpdateMoment(MomentDTO moment) {
        /**
         * 更新或新增文章，通过momentId或内容来判断
         * 如果id不为空 或 内容不为空，则为更新，否则为新增
         *
         * 如果是更新，则需要判断图片哪些是新的，哪些是旧的
         * 旧的，也就是以前上传过了，之后又不想要了，那就必须得删除
         *
         */

        /**
         * -1说明是刚刚点击,临时状态，预设置
         */
        MomentDO m = null;
        if (moment.getMomentId() == -1 && FoodCircleConstant.TEMP_STATUS.equals(moment.getStatus())) {
            /**
             * 该状态下，很多数据都是默认的,所以直接新增即可
             */
            m = new MomentDO();
            BeanUtils.copyProperties(moment, m);
            momentMapper.insert(m);
            moment.setMomentId(m.getMomentId());
        } else {

            m = momentMapper.selectById(moment.getMomentId());
            if (m == null) {
                logger.info("要操作的文章 {} 不存在", moment.getMomentId());
                throw new MomentNotExistException();
            }

            if (m.getStatus().equals(FoodCircleConstant.VERIFYING_STATUS)) {
                logger.info("要操作的文章 {} 正在审核中,无法操作", moment.getMomentId());
                throw new MomentVerifyingException();
            }


            /**
             * 地点一旦设置就不可更改
             */
            //更新,真正的发布,存为草稿
            m = new MomentDO();
            BeanUtils.copyProperties(moment, m);
            /**
             * 标签
             */
            if (StringUtils.isNotNull(moment.getTags())) {
                String[] tags = new String[moment.getTags().size()];
                List<TagDTO> tagsList = moment.getTags();
                for (int i = 0; i < tagsList.size(); i++) {
                    tags[i] = tagsList.get(i).getTagId() + "";
                }
                m.setTags(String.join(FoodCircleConstant.SEPARATE_CHAR, tags));
            }
            //发布状态
            if (FoodCircleConstant.PUBLISH_STATUS.equals(m.getStatus())) {
                /**
                 * TODO 自动审核 或 人工审核
                 */
            }
            momentMapper.updateById(m);

            /**
             * 删除缓存，更新数据
             */
            MomentInfoDTO cache = momentCacheService.getMomentDetailInfo(m.getMomentId());
            if (StringUtils.isNotNull(cache)) {
                MomentDO c = new MomentDO();
                c.setMomentId(cache.getMomentId());
                c.setView(cache.getViewNum());
                momentMapper.updateById(c);
                momentCacheService.deleteMomentDetailInfo(m.getMomentId());
            }
        }

        return moment;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteMomentById(Long userId, Long momentId) {

        /**
         * 删除文章：
         * 1.先查出来再删除呢
         * 2.还是直接删除呢
         * 3.正在审核的文章不可修改，不可删除
         *
         * 我觉得直接删除就可以了，通过userId 和 momentId，也不会误删用户信息
         * 不可能王五删除了赵四的信息
         */

        QueryWrapper<MomentDO> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        wrapper.eq("moment_id", momentId);
        MomentDO momentDO = momentMapper.selectOne(wrapper);
        if (StringUtils.isNotNull(momentDO) && !momentDO.getStatus().equals(FoodCircleConstant.VERIFYING_STATUS)) {
            /**
             * TODO 删除图片等信息
             */
            wrapper = new QueryWrapper<>();
            wrapper.eq("user_id", userId);
            wrapper.eq("moment_id", momentId);
            momentMapper.delete(wrapper);
            /**
             * 删除缓存
             */
            momentCacheService.deleteMomentDetailInfo(momentId);
            return;
        }

        if (StringUtils.isNull(momentDO)) {
            logger.info("要删除的文章 {} 不存在", momentId);
            throw new MomentNotExistException();
        }

        if (momentDO.getStatus().equals(FoodCircleConstant.VERIFYING_STATUS)) {
            logger.info("要删除的文章 {} 正在审核中,无法操作", momentId);
            throw new MomentVerifyingException();
        }

    }

    @Override
    public MomentDTO getMomentUpdateById(Long momentId, Long userId) {
        QueryWrapper<MomentDO> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        wrapper.eq("moment_id", momentId);
        MomentDO momentDO = momentMapper.selectOne(wrapper);

        if (StringUtils.isNull(momentDO) || FoodCircleConstant.TEMP_STATUS.equals(momentDO.getStatus())) {
            logger.info("文章 {} 不存在", momentId);
            throw new MomentNotExistException();
        }

        //数据权限校验
        boolean auth = authService.authMoment(momentDO, userId);

        if (!auth) {
            logger.info("用户或游客无法查看 文章 {} ，收到权限保护", momentId);
            throw new PermissionDeniedException();
        }


        MomentDTO moment = new MomentDTO();

        //封装基本信息
        BeanUtils.copyProperties(momentDO, moment);
        //标签信息
        String[] split = momentDO.getTags().split(FoodCircleConstant.SEPARATE_CHAR);
        List<Long> ids = Arrays.stream(split).map(f -> {
            return Long.parseLong(f);
        }).collect(Collectors.toList());

        List<TagDO> tagDOS = tagMapper.selectBatchIds(ids);
        moment.setTags(new ArrayList<>());
        for (int i = 0; i < tagDOS.size(); i++) {
            TagDTO t = new TagDTO();
            BeanUtils.copyProperties(tagDOS.get(i), t);
            moment.getTags().add(t);
        }

        //TODO 图片信息


        return moment;
    }

    @Override
    public List<MomentInfoDTO> listMoment(UserRelationDO userRelation, LoginUser loginUser, UserDO userDO) {

        if (StringUtils.isNull(userDO)) {
            throw new UserNotExistException();
        }

        /**
         * 获取用户探店数据:
         * (1)如果当前是用户自己获取自己的文章列表
         *  参数：status = 60(显示状态),分页信息
         * (2)如果是用户的粉丝
         * 参数：status=60,data_scope=2
         * (3)如果是游客/非用户粉丝
         * 参数：status=60，data_scope=3
         */
        List<MomentDO> list = null;

        if (StringUtils.isNotNull(loginUser)) {
            UserDO user = loginUser.getUserDO();
            //如果是用户自己查看自己的文章列表
            if (user.getAccount().equals(userDO.getAccount())) {
                //status = 60(显示状态),分页信息
                list = momentMapper.listMoment(userDO.getUserId(), FoodCircleConstant.SHOW_STATUS, FoodCircleConstant.ONLY_ME);
            } else if (StringUtils.isNotNull(userRelation)) {
                //status=60,data_scope=2,分页信息
                //如果当前登录用户是account的粉丝
                list = momentMapper.listMoment(userDO.getUserId(), FoodCircleConstant.SHOW_STATUS, FoodCircleConstant.ONLY_FAN);
            }
        }

        //如果是游客/非用户粉丝
        if (StringUtils.isNull(loginUser) || StringUtils.isNull(userRelation)) {
            //status=60，data_scope=3,分页信息
            list = momentMapper.listMoment(userDO.getUserId(), FoodCircleConstant.SHOW_STATUS, FoodCircleConstant.ALL_FRIEND);
        }

        /**
         * 封装信息:标签，地区，用户信息
         */
        List<MomentInfoDTO> result = new ArrayList<>();


        for (MomentDO momentDO : list) {
            MomentInfoDTO m = new MomentInfoDTO();

            //文章基本信息
            m.setMomentId(momentDO.getMomentId());
            m.setDescription(momentDO.getDescription());
            m.setTitle(momentDO.getTitle());
            m.setViewNum(momentDO.getView().intValue());
            m.setCreateTime(momentDO.getCreateTime());

            //标签信息(上面有重复的，可以抽取出来)
            String tags = momentDO.getTags();
            if (StringUtils.isNotEmpty(tags)) {
                String[] split = tags.split(FoodCircleConstant.SEPARATE_CHAR);
                List<Long> ids = Arrays.stream(split).map(f -> {
                    return Long.parseLong(f);
                }).collect(Collectors.toList());
                List<TagDO> tagDOS = tagMapper.selectBatchIds(ids);
                m.setTags(new ArrayList<>());
                for (int i = 0; i < tagDOS.size(); i++) {
                    TagDTO t = new TagDTO();
                    BeanUtils.copyProperties(tagDOS.get(i), t);
                    m.getTags().add(t);
                }
            }

            //地点信息
            if (momentDO.getAddr() == 0) {
                m.setAddr(new ArrayList<>());
            } else {
                List<RegionDO> addr = regionService.getFullName(momentDO.getAddr());
                m.setAddr(addr);
            }


            //设置用户信息
            m.setAccount(userDO.getAccount());
            m.setUsername(userDO.getUsername());
            m.setAvatar(userDO.getAvatar());

            //TODO 图片信息,Mark数量,评论数量
            m.setViewNum(0);
            m.setMarkNum(0);
            m.setCommentNum(0);

            result.add(m);
        }


        return result;
    }

    @Override
    public MomentInfoDTO getMomentDetailInfo(Long userId, Long momentId) {


        /**
         * 数据权限校验：
         */
        MomentDO momentDO = momentMapper.selectById(momentId);

        if (StringUtils.isNull(momentDO)) {
            logger.info("文章 {} 不存在", momentId);
            throw new MomentNotExistException();
        }

        //数据权限校验
        boolean auth = authService.authMoment(momentDO, userId);

        if (!auth) {
            logger.info("游客或用户没有权限查看文章 {} ", momentDO.getTitle());
            throw new PermissionDeniedException();
        }

        /**
         * 先从缓存中查，查不到再去数据库中查
         */
        MomentInfoDTO m = momentCacheService.getMomentDetailInfo(momentId);

        if (StringUtils.isNotNull(m)) {
            /**
             * 增加访问量
             */
            String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
            long time = momentCacheService.getIpMoment(ip, momentId);
            //如果不为0，说明该ip短时间内访问过这篇文章，访问量不增加;否则访问量+1
            if (time == 0) {
                m.setViewNum(m.getViewNum() + 1);
                momentCacheService.insertMomentDetailInfo(m);
                momentCacheService.insertIpMoment(ip, momentId);
                /**
                 * TODO 定时从redis中获取数据更新数据库信息
                 */
            }
            return m;
        }


        /**
         * TODO 可做缓存，因为文章其实修改不是很频繁
         */

        m = new MomentInfoDTO();


        //文章基本信息
        m.setMomentId(momentDO.getMomentId());
        m.setContent(momentDO.getContent());
        m.setTitle(momentDO.getTitle());
        m.setViewNum(momentDO.getView().intValue());
        m.setCreateTime(momentDO.getCreateTime());

        //标签信息(上面有重复的，可以抽取出来)
        String tags = momentDO.getTags();
        if (StringUtils.isNotEmpty(tags)) {
            String[] split = tags.split(FoodCircleConstant.SEPARATE_CHAR);
            List<Long> ids = Arrays.stream(split).map(f -> {
                return Long.parseLong(f);
            }).collect(Collectors.toList());
            List<TagDO> tagDOS = tagMapper.selectBatchIds(ids);
            m.setTags(new ArrayList<>());
            for (int i = 0; i < tagDOS.size(); i++) {
                TagDTO t = new TagDTO();
                BeanUtils.copyProperties(tagDOS.get(i), t);
                m.getTags().add(t);
            }
        }

        //地点信息
        if (momentDO.getAddr() == 0) {
            m.setAddr(new ArrayList<>());
        } else {
            List<RegionDO> addr = regionService.getFullName(momentDO.getAddr());
            m.setAddr(addr);
        }


        UserDO userDO = userMapper.selectById(momentDO.getUserId());


        //设置用户信息
        m.setAccount(userDO.getAccount());
        m.setUsername(userDO.getUsername());
        m.setAvatar(userDO.getAvatar());

        //TODO 图片信息,Mark数量,评论数量
        m.setViewNum(momentDO.getView() + 1);
        m.setMarkNum(0);
        //评论变化波动大
        m.setCommentNum(0);

        //TODO 图片信息

        momentCacheService.insertMomentDetailInfo(m);

        return m;
    }

    @Override
    public MomentDO getMomentById(Long momentId) {
        if (StringUtils.isNull(momentId) || momentId.equals(0)) {
            logger.info("文章 {} 不存在", momentId);
            throw new MomentNotExistException();
        }
        MomentDO momentDO = momentMapper.selectById(momentId);
        if (StringUtils.isNull(momentDO)) {
            logger.info("文章 {} 不存在", momentId);
            throw new MomentNotExistException();
        }
        return momentDO;
    }
}